const path = require('path');
const async = require('async');
const copyDir = require('recursive-copy');
const del = require('del');
const { Listr } = require('listr2');
const cli = require('pixl-cli');
const simpleGit = require('simple-git/promise');
const boxen = require('boxen');
const utils = require('./utils');
const fs = require('fs/promises');


const processors = {
    base: require('./processor/base'),
    maven: require('./processor/maven'),
    reactjs: require('./processor/reactjs'),
};

const TEMPLATE_DEFS = {
    "1": {
        name: "Spring Cloud Project",
        desc: "基于 ugeez-commons 的 Spring Cloud 工程模板",
        comment: "JDK 1.8 / Maven",
        type: "java",
        url: "https://gitee.com/lgks701/ugeez-starterkit-template-java-spring-cloud-project.git",
        subTasks: processors.maven.genSubTasks,
        preBuildProcess: processors.base.process,
        buildProcess: processors.maven.process,
    },
    "2": {
        name: "Spring Web Project",
        desc: "基于 ugeez-commons 的单体 Springboot Web 工程模板",
        comment: "JDK 1.8 / Maven",
        type: "java",
        url: "https://gitee.com/lgks701/ugeez-starterkit-template-java-spring-web-project.git",
        subTasks: processors.maven.genSubTasks,
        preBuildProcess: processors.base.process,
        buildProcess: processors.maven.process,
    },
    "11": {
        name: "React CMS Project (Micro)",
        desc: "采用微前端架构的后台React CMS工程模板",
        comment: "JDK 1.8 / Maven",
        type: "java",
        url: "https://gitee.com/lgks701/ugeez-starterkit-template-micro-cms-webapp-project.git",
        subTasks: processors.reactjs.genSubTasks,
        preBuildProcess: processors.base.process,
        buildProcess: processors.reactjs.process,
    },
    "12": {
        name: "React CMS Project (Single)",
        desc: "采用微前端架构的后台React CMS工程模板 (单体模板)",
        comment: "JDK 1.8 / Maven",
        type: "java",
        url: "https://gitee.com/lgks701/ugeez-starterkit-template-micro-cms-webapp-project.git",
        cloneOptions: { "--branch": "single-module" },
        subTasks: processors.reactjs.genSubTasks,
        preBuildProcess: processors.base.process,
        buildProcess: processors.reactjs.process,
    }
};

const TEMPLATES = [
    ["No", "Name", "Description", "Requirement"],
    // [ "1", "Spring Cloud Project", "基于 ugeez-commons 的 Spring Cloud 工程模板", "" ],
    // [ "2", "website", "网站模板项目，提供了用户账户注册、登录/登出，使用数据库创建用户数据，登录会话管理的示例", "^node v7.0|async/await", "nodejs"]
];

(() => {
    let temps = [];
    for (let key in TEMPLATE_DEFS) {
        let def = TEMPLATE_DEFS[key];
        temps.push([key, def.name, def.desc, def.comment || ""]);
    }
    temps = temps.sort((a, b) => Number(a[1]) > Number(a[2]));
    TEMPLATES.push.apply(TEMPLATES, temps);
})();

const findTemplate = (noOrName) => {
    for (let i = 1; i < TEMPLATES.length; i++) {
        if (TEMPLATES[i][0] == noOrName || TEMPLATES[i][1] == noOrName) return TEMPLATE_DEFS[TEMPLATES[i][0]];
    }
    return undefined;
}

exports.exec = function (runArgs, done) {
    let dir = process.cwd();
    let template = undefined;
    let project = undefined;
    let templateDef;

    let ARGS = {};
    runArgs.forEach(function (val, i) {
        if (val.startsWith("--")) {
            let temp = val.split("=");
            ARGS[temp[0].substring(2)] = temp[1] == undefined ? true : temp[1];
        }
    });

    project = ARGS['project'];
    template = ARGS['template'];

    if (!project) {
        project = dir.substring(dir.lastIndexOf(path.sep) + 1);
    }

    let pdir = path.join(dir, '');

    // console.log(dir);
    // console.log(template);
    // console.log(project);
    // console.log(ARGS);
    // return;


    //let tmp = require('tmp');
    //tmp.setGracefulCleanup();

    let tmpRoot = path.join(pdir, ".tmp");
    let tmpFolder;

    function clearAll(callBack) {
        // console.log("clean tmp files...");
        setTimeout(function () {
            let p = [];
            p.push(function (cb) {
                del([tmpRoot], { force: true }).then(function () {
                    cb();
                }).catch(function (err) {
                    console.error(err);
                    cb();
                });
            });
            async.parallel(p, function () {
                callBack && callBack();
            });
        }, 200);
    }

    let run = () => {

        const tasks = [
            {
                title: 'choose a template for creating project ---> ' + templateDef.name,
                task: (ctx, task) => {

                    for (let key in ARGS) {
                        ctx[key] = ARGS[key];
                    }

                    ctx.pdir = pdir;
                    ctx.tmpRoot = tmpRoot;
                    ctx.tmpFolder = tmpFolder;
                    ctx.project = project;
                    ctx.template = template;
                    ctx.templateDef = templateDef;

                    if (templateDef.subTasks) {
                        return task.newListr(templateDef.subTasks(ctx, task));
                    } else {
                        return new Promise(resolve => resolve());
                    }
                }
            },
            {
                title: 'create folders',
                task: async () => {
                    await del([tmpRoot]);

                    await utils.lookUpDir(pdir, async (filename, filePath) => {
                        await del([filePath]);
                    });

                    tmpFolder = path.join(tmpRoot, "template_" + Math.round(100000 * Math.random()) + "_" + Date.now());
                    await fs.mkdirp(tmpFolder);
                }
            },
            {
                title: 'download template project from remote repository',
                task: async (ctx, task) => {
                    await simpleGit().clone(templateDef.url, tmpFolder, templateDef.cloneOptions);

                    await del([path.resolve(tmpFolder, '.git')]);

                    await copyDir(tmpFolder, pdir);

                    const files = await fs.readdir(tmpFolder);
                    for ( let filename of files) {
                        let filePath = path.resolve(pdir, filename);
                        if (filePath.startsWith('.') && !await utils.checkFileExists(filePath)) {
                            let fstat = await fs.lstat(filePath);
                            if (!fstat.isDirectory) {
                                await fs.copyFile(path.resolve(tmpFolder, filename), filePath);
                            }
                        }
                    }

                    await del([tmpRoot]);
                }
            },
            {
                title: `build process...`,
                task: async (ctx, task) => {
                    if (templateDef.preBuildProcess) {
                        await templateDef.preBuildProcess(ctx, task);
                    }

                    if (templateDef.buildProcess) {
                        await templateDef.buildProcess(ctx, task);
                    }
                }
            },
            {
                title: 'clean and completed',
                task: () => new Promise((resolve) => {
                    clearAll(function () {
                        resolve();
                    });
                })
            }
        ];


        new Listr(tasks, { concurrent: false }).run().then(() => {
            setTimeout(() => {
                console.log(boxen('init template successfully!', { padding: 1, borderStyle: 'classic' }));
            }, 100);
        }).catch(err => {
            console.error(err);
        });
    }

    let chooseTemplate = (callBack) => {
        cli.prompt("Which template your want to init?\n" + cli.table([...TEMPLATES]) + "\nchoose > ", "", (noOrName) => {
            // cli.print("Hello " + name + "!\n");
            templateDef = findTemplate(noOrName);
            if (!templateDef) {
                cli.warn("Invalid template choose. Please input the correct No or Name.\n");
                return setTimeout(() => {
                    chooseTemplate();
                }, 1000);
            }
            callBack && callBack();
        });
    }

    if (!template) {
        chooseTemplate(() => run());
    } else {
        run();
    }

}